package com.harmontronics.hanma.paas.paas.domain.iam.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.harmontronics.hanma.paas.paas.consts.NumberEnum;
import com.harmontronics.hanma.paas.paas.domain.iam.entity.HmAction;
import com.harmontronics.hanma.paas.paas.domain.iam.entity.PermAction;
import com.harmontronics.hanma.paas.paas.domain.iam.entity.PermActionList;
import com.harmontronics.hanma.paas.paas.domain.organization.entity.valueobject.Constants;
import com.harmontronics.hanma.paas.paas.domain.iam.entity.valueobject.HmPermFields;
import com.harmontronics.hanma.paas.paas.domain.iam.entity.valueobject.HmUserGroupFileds;
import com.harmontronics.hanma.paas.paas.domain.iam.entity.valueobject.HmUserGroupManageFields;
import com.harmontronics.hanma.paas.paas.domain.iam.entity.valueobject.HmUserGroupMemberFields;
import com.harmontronics.hanma.paas.paas.domain.iam.entity.valueobject.HmUserGroupRoleFields;
import com.harmontronics.hanma.paas.paas.domain.organization.entity.valueobject.I18nKeyEnum;
import com.harmontronics.hanma.paas.paas.domain.iam.repository.mapper.HmRolePermMapper;
import com.harmontronics.hanma.paas.paas.domain.iam.repository.mapper.HmUserGroupManageMapper;
import com.harmontronics.hanma.paas.paas.domain.iam.repository.mapper.HmUserGroupMapper;
import com.harmontronics.hanma.paas.paas.domain.iam.repository.mapper.HmUserGroupMemberMapper;
import com.harmontronics.hanma.paas.paas.domain.iam.repository.mapper.HmUserGroupRoleMapper;
import com.harmontronics.hanma.paas.paas.domain.iam.repository.persistence.HmPermRepository;
import com.harmontronics.hanma.paas.paas.domain.iam.entity.HmPerm;
import com.harmontronics.hanma.paas.paas.domain.iam.repository.po.HmPermActionPO;
import com.harmontronics.hanma.paas.paas.domain.iam.repository.po.HmUserGroupManagePO;
import com.harmontronics.hanma.paas.paas.domain.iam.repository.po.HmUserGroupMemberPO;
import com.harmontronics.hanma.paas.paas.domain.iam.repository.po.HmUserGroupPO;
import com.harmontronics.hanma.paas.paas.domain.iam.repository.po.HmUserGroupRolePO;
import com.harmontronics.hanma.paas.paas.domain.organization.service.HmOrgService;
import com.harmontronics.hanma.paas.paas.exception.ErrorKeyException;
import com.harmontronics.hanma.paas.paas.token.AppUserTokenKit;
import com.harmontronics.hanma.paas.paas.token.UserInfo;
import com.harmontronics.hanma.paas.paas.utils.RequestUtils;
import java.util.ArrayList;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.harmontronics.hanma.paas.paas.common.PageBase;

import com.harmontronics.hanma.paas.paas.domain.iam.repository.mapper.HmPermMapper;
import com.harmontronics.hanma.paas.paas.domain.iam.repository.po.HmPermPO;
import java.util.List;

@Service("hmPermService")
@DS("#header.App-Unique")
public class HmPermService{

    @Autowired
    private HmPermRepository hmPermRepository;

    @Autowired
    private HmPermMapper hmPermMapper;

    @Autowired
    private HmPermActionService hmPermActionService;

    @Autowired
    private HmOrgService hmOrgService;

    @Autowired
    private HmUserGroupMemberMapper hmUserGroupMemberMapper;

    @Autowired
    private HmUserGroupManageMapper hmUserGroupManageMapper;

    @Autowired
    private HmUserGroupManageService hmUserGroupManageService;

    @Autowired
    private HmUserGroupMapper hmUserGroupMapper;

    @Autowired
    private HmUserGroupRoleMapper hmUserGroupRoleMapper;

    @Autowired
    private HmRolePermMapper hmRolePermMapper;

    @Autowired
    private HmActionService hmActionService;


    @Autowired
    private AppUserTokenKit appUserTokenKit;


    public HmPerm findById(Long id){
        QueryWrapper<HmPermPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(HmPermFields.ID,id).eq(HmPermFields.DELETED,NumberEnum.ZERO.getNum());
        HmPermPO po =   hmPermRepository.getOne(queryWrapper);
        return BeanUtil.toBean(po,HmPerm.class);
    }

    public void save(HmPerm hmPerm){
        savePerm(hmPerm);

        if (CollectionUtils.isNotEmpty(hmPerm.getActions())){
            hmPerm.getActions().forEach(x ->{
                HmAction action = hmActionService.getAction(hmPerm.getAppId(), x.getAction());
                Long actionId = null;
                if (Objects.isNull(action)){
                    actionId = hmActionService.create(x);
                }else {
                    actionId = action.getId();
                }
                if (Objects.nonNull(actionId)){
                    x.setId(actionId);
                    HmPermActionPO permAction = buildPermAction(hmPerm.getId(), actionId);
                    hmPermActionService.create(permAction);
                }
            });
        }

        if (CollectionUtils.isNotEmpty(hmPerm.getChildren())){
            hmPerm.getChildren().forEach(x ->{
                x.setParentId(hmPerm.getId());
                save(x);
            });
        }
    }

    private void savePerm(HmPerm permDto) {
        HmPermPO perm = BeanUtil.toBean(permDto, HmPermPO.class);

        Long parentId = permDto.getParentId();

        HmPermPO parentPerm = null;
        if (Objects.nonNull(parentId)) {
            parentPerm = hmPermMapper.selectById(parentId);
        }

        // 组装数据
        StringBuilder parentPath = new StringBuilder();
        if (parentPerm != null) {
            if (parentPerm.getParentIds() != null) {
                parentPath.append(parentPerm.getParentIds());
            }
            parentPath
                    .append(Constants.LEFT_SQUARE_BRACKETS)
                    .append(parentPerm.getId())
                    .append(Constants.RIGHT_SQUARE_BRACKETS);
            perm.setParentId(parentPerm.getId());
        }
        String parentIdStr = parentPath.toString();
        perm.setParentIds(parentIdStr);

        //判断菜单层级，必须小于三层
        String[] parentIds = parentIdStr.split(Constants.PARENTID);
        if (parentIds.length >= 3) {
            //throw new ErrorKeyException(Constants.MODULE_ID + Errors.ERROR_CODE_3000);
        }

        perm.setDeleted(NumberEnum.ZERO.getNum());
        hmPermMapper.insert(perm);

        permDto.setId(perm.getId());
    }

    private HmPermActionPO buildPermAction(Long permId, Long actionId ){
        HmPermActionPO permAction = new HmPermActionPO();
        permAction.setPermId(permId);
        permAction.setActionId(actionId);
        permAction.setDeleted(0);
        return permAction;
    }

    public void update(HmPerm hmPerm){
            HmPermPO po =  BeanUtil.toBean(hmPerm,HmPermPO.class);
            hmPermRepository.updateById(po);
    }


    public void updatePermAndAction(Long perId, List<Long> actionIdList) {
        if (perId != null) {
            // 更新按钮操作
            hmPermActionService.updateWithPermId(perId,actionIdList);
        }
    }

    public void updatePerm(HmPerm statusDto) {
        LambdaQueryWrapper<HmPermPO> queryWrapper = new QueryWrapper<HmPermPO>().lambda();
        queryWrapper.eq(HmPermPO::getId, statusDto.getId());


        List<HmPermPO> perms = hmPermMapper.selectList(queryWrapper);
        if (CollectionUtils.isNotEmpty(perms)){
            perms.forEach(perm -> {
                perm.setStatus(statusDto.getStatus());
            });
            hmPermRepository.updateBatchById(perms);
        }
    }

    public void remove(List<Long> idList){
        List<HmPermPO> updateList = hmPermMapper.selectBatchIds(idList);
        updateList.forEach(
                perm -> {
                    perm.setDeleted(NumberEnum.ONE.getNum());
                    hmPermMapper.updateById(perm);
                });

        List<HmPermActionPO> permActionsByPermIds = hmPermActionService.getPermActionsByPermIds(idList);

        if (CollectionUtils.isNotEmpty(permActionsByPermIds)) {
            permActionsByPermIds.forEach(permAction -> {
                permAction.setDeleted(NumberEnum.ONE.getNum());
            });
            hmPermActionService.updateBatchById(permActionsByPermIds);
        }
    }

    public List<HmPerm> getList(){
        List<HmPermPO> pos =  hmPermRepository.list();
        return Convert.toList(HmPerm.class,pos) ;
    }

    public PageBase<HmPerm> getList(int pageNo,int pageSize){
        Page<HmPermPO> page = new Page<>(pageNo, pageSize);
        IPage<HmPermPO> resultPage =
                    hmPermRepository.selectPage(Wrappers.emptyWrapper(),page);
        return PageBase.from(resultPage,HmPerm.class);
    }

    public List<PermActionList> selectAllPermAndAction(Long appId, Integer status) {
        // 根据status进行查询
        List<PermActionList> permActionList = Lists.newArrayList();

        if (status == null) {
            status = NumberEnum.ZERO.getNum();
        }

        if (NumberEnum.TWO.getNum() != status) {
            permActionList = hmPermMapper.selectAllPermAndAction(appId, status);
        } else {
            permActionList = composeAllPermAction(appId, NumberEnum.ZERO.getNum());
        }
        for(PermActionList dto:permActionList){
            disableStatus(dto);
        }
        return permActionList;
    }


    private List<PermActionList> composeAllPermAction(Long appId, Integer status) {
        List<PermActionList> permActionList = hmPermMapper.selectAllPermAndAction(appId, status);
        List<PermActionList> removeList = new ArrayList<>();
        for (PermActionList permActionListDto : permActionList) {
            // 只查看 状态1 的所有节点, 为2的要显示，不需要处理
            if (permActionListDto.getStatus() == NumberEnum.ONE.getNum()) {
                List<PermAction> children = permActionListDto.getChildren();
                List<PermAction> removeChildren = new ArrayList<>();
                // 判断是否有子节点
                if (CollectionUtils.isNotEmpty(children)) {
                    for (PermAction child : children) {
                        if (child.getStatus() == NumberEnum.ONE.getNum()) {
                            List<PermAction> thirdPermList = child.getChildren();
                            List<PermAction> removeThird = new ArrayList<>();
                            // 判断是否有子节点
                            if (CollectionUtils.isNotEmpty(thirdPermList)) {
                                for (PermAction thirdPerm : thirdPermList) {
                                    if (thirdPerm.getStatus() == NumberEnum.ONE.getNum()) {
                                        // 状态为1 不需要，添加到移除的节点中
                                        removeThird.add(thirdPerm);
                                    }
                                }
                                // 删除三级节点中的数据
                                child.getChildren().removeAll(removeThird);
                            } else {
                                // 状态为1 且 没有子节点说明当前节点可以删除二级菜单
                                removeChildren.add(child);
                            }
                        }
                    }
                    permActionListDto.getChildren().removeAll(removeChildren);
                } else {
                    // 状态为1 且 没有子节点说明当前节点可以删除一级菜单
                    removeList.add(permActionListDto);
                }
            }
        }
        permActionList.removeAll(removeList);
        return permActionList;
    }

    private void disableStatus(PermActionList listDto){
        if(listDto.getStatus() ==null || listDto.getStatus() == 2){
            if(CollectionUtils.isNotEmpty(listDto.getChildren())){
                for(PermAction child:listDto.getChildren()){
                    child.setStatus(2);
                    disableStatus(child);
                }
            }
        }else{
            if(CollectionUtils.isNotEmpty(listDto.getChildren())){
                for(PermAction child:listDto.getChildren()){
                    disableStatus(child);
                }
            }
        }
    }

    private void disableStatus(PermAction actionDto){
        if(actionDto.getStatus() == null||actionDto.getStatus() == 2){
            if(CollectionUtils.isNotEmpty(actionDto.getChildren())){
                for(PermAction child:actionDto.getChildren()){
                    child.setStatus(2);
                    disableStatus(child);
                }
            }
        }
    }

    public List<PermActionList> getPermActionList(Long userId, Long appId){
        UserInfo userInfo = appUserTokenKit.getUserInfo();
        if(userInfo.isAdmin()){
            return hmRolePermMapper.selectAllPermActions();
        }

        List<PermActionList> result = new ArrayList<>();
        //1. 获取当前用户所在的group: 包含两部分 group_member 和 group_manager
        List<Long> groupIds = getGroupIds(userId, appId);

        //2. 根据groupId 获取角色，group_role
        if (CollectionUtils.isEmpty(groupIds)){
            return result;
        }

        List<Long> roleIds = getRoleIds(groupIds);

        if (CollectionUtils.isEmpty(roleIds)){
            return result;
        }

        //3. 获取权限
        roleIds.forEach(roleId ->{
            List<PermActionList> permActionListDtos = hmRolePermMapper.selectPermActionWithRoleId(roleId);
            result.addAll(permActionListDtos);
        });

        return result;
    }

    private List<Long> getGroupIds(Long userId, Long appId){
        List<Long> userGroupIds = new ArrayList<>(128);
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq(HmUserGroupMemberFields.ROLE_ID, NumberEnum.ZERO.getNum());
        queryWrapper.eq(HmUserGroupMemberFields.UNION_ID, userId);
        queryWrapper.eq(HmUserGroupMemberFields.DELETED, NumberEnum.ZERO.getNum());
        List<HmUserGroupMemberPO> groupMembers = hmUserGroupMemberMapper.selectList(queryWrapper);

        if (CollectionUtils.isNotEmpty(groupMembers)){
            userGroupIds.addAll(groupMembers.stream().map(HmUserGroupMemberPO::getUserGroupId).collect(Collectors.toList()));
        }

        List<Long> userOrgIds = hmOrgService.selectOrgParentIdWithUserId(userId);
        List<Long> userGroupIdsTemp =
                hmUserGroupManageService.selectGroupIdsWithOrgIdAndUserId(userOrgIds, Long.valueOf(userId));

        if (CollectionUtils.isNotEmpty(userGroupIdsTemp)){
            userGroupIds.addAll(userGroupIdsTemp);
        }


        queryWrapper = new QueryWrapper();
        queryWrapper.eq(HmUserGroupManageFields.USER_ID, userId);
        queryWrapper.eq(HmUserGroupManageFields.DELETED, NumberEnum.ZERO.getNum());

        List<HmUserGroupManagePO> groupManages = hmUserGroupManageMapper.selectList(queryWrapper);

        if (CollectionUtils.isNotEmpty(groupManages)){
            userGroupIds.addAll(groupManages.stream().map(HmUserGroupManagePO::getUserGroupId).collect(Collectors.toList()));
        }

        // 过滤掉其他appId
        queryWrapper = new QueryWrapper();
        queryWrapper.eq(HmUserGroupFileds.APP_ID, appId);

        if (CollectionUtils.isNotEmpty(userGroupIds)){
            queryWrapper.in(HmUserGroupFileds.ID, userGroupIds);
        }

        queryWrapper.eq(HmUserGroupFileds.DELETED, NumberEnum.ZERO.getNum());
        List<HmUserGroupPO> userGroups = hmUserGroupMapper.selectList(queryWrapper);

        return userGroups.stream().map(HmUserGroupPO::getId).collect(Collectors.toList());
    }

    private List<Long> getRoleIds(List<Long> groupIds) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.in(HmUserGroupRoleFields.GROUP_ID, groupIds);
        queryWrapper.eq(HmUserGroupRoleFields.DELETED, NumberEnum.ZERO.getNum());
        List<HmUserGroupRolePO> userGroupRoles = hmUserGroupRoleMapper.selectList(queryWrapper);

        return userGroupRoles.stream().map(HmUserGroupRolePO::getRoleId).collect(Collectors.toList());
    }

    public void validateField(long id, Long appId, String key, String value, long parentId) {
        QueryWrapper<HmPermPO> wrapper = new QueryWrapper<>();
        wrapper.eq(key, value);
        wrapper.eq(HmPermFields.APP_ID, appId);
        if (parentId > NumberEnum.ZERO.getNumLong()) {
            wrapper.eq(HmPermFields.PARENT_ID, parentId);
        }

        // 修改
        if (NumberEnum.ZERO.getNumLong() != id) {
            wrapper.ne(HmPermFields.ID, id);
        }

        validateFieldImpl(key, wrapper);
    }

    private void validateFieldImpl(String key, QueryWrapper<HmPermPO> wrapper) {
        HmPermPO perm = hmPermMapper.selectOne(wrapper);

        if (Optional.ofNullable(perm).isPresent()) {
            throw new ErrorKeyException(I18nKeyEnum.CURRENT_ROLE_EXIST);
        }
    }

}